<template>
  <!-- #ifndef APP-PLUS-NVUE -->
  <view class="cache-loadimage">
    <view v-if="showLoading" class="loading" :style="loadingStyle">
      <uni-icons type="spinner-cycle" size="28" color="#ccc" />
    </view>
    <image class="origin" :src="cacheImgUrl" :webp="webp" :mode="mode" :draggable="draggable" :fade-show="fadeShow"
           :lazy-load="lazyLoad" :show-menu-by-longpress="showMenuByLongpress"
           :class="{
             'no-transition': !openTransition,
             'show-transition': showTransition && openTransition,
           }" @load="load($event)" @error="error($event)" @tap="previewImage"
    />
    <view v-if="showFailed" class="fail" :style="failStyle" />
  </view>
  <!-- #endif -->
  <!-- #ifdef APP-PLUS-NVUE -->
  <image class="origin no-transition" :style="{ width: `${imgWidth}px`, height: `${imgHeight}px` }" :src="cacheImgUrl"
         :webp="webp" :mode="mode" :fade-show="fadeShow" :lazy-load="lazyLoad" :show-menu-by-longpress="showMenuByLongpress"
         :draggable="draggable" @load="load($event)" @error="error($event)" @tap="previewImage"
  />
  <!-- #endif -->
</template>

<script>
import { ImgCache } from './js/imageCache.js'

export default {
  // 将自定义节点设置成虚拟的，更加接近Vue组件的表现，能更好的使用flex属性
  options: {
    virtualHost: true,
    // externalClasses: 'cache-image',
    // styleIsolation: "shared",
  },
  props: {
    src: {
      type: String,
    },
    width: {
      type: Number,
      default: 300,
    },
    height: {
      type: Number,
      default: 200,
    },
    webp: {
      type: Boolean,
      default: false,
    },
    loadingStyle: {
      type: Object,
      default() {
        return {}
      },
    },
    failStyle: {
      type: Object,
      default() {
        return {}
      },
    },
    mode: {
      type: String,
      default: 'scaleToFill',
    },
    // 是否能拖动图片
    draggable: {
      type: Boolean,
      default: true,
    },
    showMenuByLongpress: {
      type: Boolean,
      default: false,
    },
    fadeShow: {
      type: Boolean,
      default: true,
    },
    lazyLoad: {
      type: Boolean,
      default: true,
    },
    isPreview: {
      type: Boolean,
      default: false,
    },
    loadingMode: {
      type: String,
      default: 'looming-gray',
    },
    openTransition: {
      type: Boolean,
      default: true,
    },
    placeholder: {
      type: String,
      default: '',
    },
    noCache: {
      type: Boolean,
      default: false,
    },
  },
  emits: ['loadCompleted', 'previewImage', 'load', 'error'],
  data() {
    return {
      cacheImgUrl: '',
      loadStatus: 'loading', // /加载中，加载成功，加载失败
      showTransition: false,
    }
  },
  computed: {
    imgWidth() {
      return uni.upx2px(this.width)
    },
    imgHeight() {
      return uni.upx2px(this.height)
    },
    showLoading() {
      return this.loadStatus === 'loading'
    },
    showFailed() {
      return this.loadStatus === 'failed'
    },
  },
  watch: {
    // 监听URL变化
    src: {
      handler(src) {
        src && this.convert(src)
      },
      immediate: true,
    },
  },
  methods: {
    async convert(src) {
      if (/http:|https:/.test(src)) {
        // 判断图片是否存在缓存
        const cacheUrl = await ImgCache.getCache(src)
        this.cacheImgUrl = cacheUrl
        this.$emit('loadCompleted', cacheUrl)
      }
      else {
        this.cacheImgUrl = src
      }
    },
    previewImage() {
      this.$emit('previewImage', this.cacheImgUrl)
      if (!this.isPreview) {
        return
      }
      uni.previewImage({
        count: 1,
        current: 0,
        urls: [this.cacheImgUrl],
      })
    },
    load(e) {
      this.loadStatus = 'loaded'
      this.showTransition = true
      this.$emit('load', e)
    },
    error(e) {
      this.loadStatus = 'failed'
      this.$emit('error', e)
    },
  },
}
</script>

<style scoped>
.cache-loadimage {
  display: flex;
  position: relative;
  /* #ifndef APP-PLUS-NVUE */
  width: 100%;
  height: 100%;
  /* #endif */
}

.loading,
.fail {
  position: absolute;
  left: 0;
  top: 0;
  right: 0;
  bottom: 0;
  width: 100%;
  height: 100%;
}

/* 渐变过渡效果处理 */
.origin {
  position: absolute;
  left: 0;
  top: 0;
  right: 0;
  bottom: 0;
  width: auto;
  height: auto;
  will-change: transform;
  opacity: 0;
}

.show-transition {
  transition: opacity 1.6s;
  opacity: 1;
}

.no-transition {
  opacity: 1;
}

/* 加载失败、加载中的占位图样式控制 */
.fail {
  /* background-color: #e3e3e3; */
  /* animation: looming-gray 3s infinite linear; */
  background: url('./image/loadfail.svg') no-repeat center;
  background-size: contain;
}

@keyframes rotate {
  0% {
    transform: rotate(0);
  }

  100% {
    transform: rotate(360deg);
  }
}

.loading {
  display: flex;
  justify-content: center;
  align-items: center;
}

.loading-rotate {
  animation: 2s rotate linear infinite normal;
}

/* 动态灰色若隐若现 */
@keyframes looming-gray {
  0% {
    background-color: #e3e3e3aa;
  }

  50% {
    background-color: #e3e3e3;
  }

  100% {
    background-color: #e3e3e3aa;
  }
}

/* 骨架屏1 */
.skeleton-1 {
  background-color: #e3e3e3;
  background-image: linear-gradient(
    100deg,
    rgba(255, 255, 255, 0),
    rgba(255, 255, 255, 0.2) 50%,
    rgba(255, 255, 255, 0) 80%
  );
  background-size: 100rpx 100%;
  background-repeat: repeat-y;
  background-position: 0 0;
  animation: skeleton-1 0.6s infinite;
}

@keyframes skeleton-1 {
  to {
    background-position: 200% 0;
  }
}

/* 骨架屏2 */
.skeleton-2 {
  background-image: linear-gradient(-90deg, #fefefe 0%, #e6e6e6 50%, #fefefe 100%);
  background-size: 400% 400%;
  background-position: 0 0;
  animation: skeleton-2 1.2s ease-in-out infinite;
}

@keyframes skeleton-2 {
  to {
    background-position: -135% 0;
  }
}

@keyframes fadeIn {
  from {
    filter: blur(10px);
  }

  to {
    filter: blur(0px);
  }
}

.fade-in {
  animation: fadeIn 0.3s ease-in;
}

@keyframes bounce-in {
  0% {
    transform: scale(0.8);
  }

  100% {
    transform: scale(1);
    opacity: 1;
  }
}

.transform-in {
  opacity: 0;
  animation: bounce-in 0.5s ease-in-out forwards;
}
</style>
